package com.wechat.page.chat.misc;

import com.google.common.util.concurrent.AtomicDouble;
import com.swak.fx.support.Display;
import com.swak.fx.support.ui.UI;
import com.swak.fx.support.ui.UIScrollPaneInner;
import com.swak.fx.support.ui.UISpinner;

import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Cursor;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Text;

/**
 * 加载状态
 * 
 * @author 618lf
 */
public class Loading extends StackPane {

	private final String[] CHAT_STYLE_CLASS = { "chatting-page__chat", "chatting-page__loading" };
	private BooleanProperty loadingProperty = new SimpleBooleanProperty(false);
	private ObjectProperty<Phase> phaseProperty = new SimpleObjectProperty<>(Phase.Init);
	private final UIScrollPaneInner scroll;
	private final Pane content;

	private Text text;
	private UISpinner loading;
	private double scrollValue = Double.MIN_VALUE;

	private AtomicDouble bottom = new AtomicDouble(0);

	public Loading(UIScrollPaneInner scroll) {
		this.getStyleClass().addAll(CHAT_STYLE_CLASS);
		this.scroll = scroll;
		this.content = (Pane) scroll.getContent();
		this.text = new Text("查看更多消息");
		this.text.setCursor(Cursor.HAND);
		this.text.setFill(UI.Colors.Primary);
		this.loading = new UISpinner();
		this.loading.setRadius(14);
		StackPane.setMargin(this.text, new Insets(10));
		StackPane.setAlignment(this.text, Pos.CENTER);
		StackPane.setAlignment(this.loading, Pos.CENTER);
		this.init();
	}

	private void init() {
		this.loadingProperty.bind(Bindings.createBooleanBinding(() -> {
			return this.phaseProperty.get() == Phase.Loading;
		}, this.phaseProperty));
		this.phaseProperty.addListener((ob, o, n) -> this.onPhaseChange(n));
		this.scroll.addEventHandler(ScrollEvent.SCROLL, (e) -> this.onScrollHandle(this.scroll.vvalueProperty().get()));
		this.addEventHandler(MouseEvent.MOUSE_CLICKED, (e) -> this.onNext());
	}

	private void onScrollHandle(double scroll) {

		// 第一次到达
		if (scroll == 0 && this.phaseProperty.get() == Phase.Attach // 基本条件
				&& this.scrollValue > scroll) {
			this.scrollValue = scroll;
			return;
		}

		// 第二次到达
		if (scroll == 0 && this.phaseProperty.get() == Phase.Attach // 基本条件
				&& this.scrollValue == scroll) {
			this.onNext();
			this.scrollValue = Double.MIN_VALUE;
			return;
		}
	}

	private void onPhaseChange(Phase phase) {
		if (phase == Phase.Init) {
			this.getChildren().remove(this.text);
			this.getChildren().remove(this.loading);
			this.content.getChildren().remove(this);
			this.scrollValue = Double.MIN_VALUE;
			this.bottom.set(0);
		} else if (phase == Phase.Attach) {
			this.content.getChildren().remove(this);
			this.content.getChildren().add(0, this);
			this.getChildren().add(this.text);
			this.getChildren().remove(this.loading);
		} else if (phase == Phase.Loading) {
			this.getChildren().remove(this.text);
			this.getChildren().add(this.loading);
		}
	}

	private void onNext() {
		Display.runUI(() -> {
			Phase phase = this.phaseProperty.get();
			if (phase == Phase.Attach && this.content.getChildren().size() > 0
					&& this.content.getChildren().get(0) == this) {
				this.bottom.set(this.scroll.scrollBottom());
				this.phaseProperty.set(Phase.Loading);
			}
		});
	}

	public void reset() {
		Display.runUI(() -> {
			this.phaseProperty.set(Phase.Init);
		});
	}

	public void attach() {
		Display.runUI(() -> {
			this.phaseProperty.set(Phase.Attach);
		});
	}

	public void finish() {
		Display.runUI(() -> {
			this.scroll.scrollToBottom(this.bottom.get());
		});
	}

	public BooleanProperty loadingProperty() {
		return this.loadingProperty;
	}

	enum Phase {
		Init, Attach, Loading
	}
}
